//////////////////////////////////////////////////////////////////////////////////
//	Copyright 2011 by Yosef Grabivker, ryuho@homenetworksoft.com
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//////////////////////////////////////////////////////////////////////////////////

#include <wx/wx.h>
#include <wx/textdlg.h>
#include "persistenlist.h"
#include "utils.h"
#include "listpaircontroller.h"
#include "macinputdlg.h"
#include "sysdepapi.h"
#include "rcmdapp.h"
#include "mainwnd.h"

enum cIDS {cIDAddButton=8200, cIDRemoveButton, cIDBlockOthers, cIDEditButton };

BEGIN_EVENT_TABLE(CPersistenList, wxPanel)
	EVT_BUTTON(cIDAddButton,		CPersistenList::OnAdd)
	EVT_BUTTON(cIDEditButton,		CPersistenList::OnEdit)
	EVT_BUTTON(cIDRemoveButton,		CPersistenList::OnRemove)
	EVT_CHECKBOX(cIDBlockOthers,	CPersistenList::OnBlockAll) 
	EVT_UPDATE_UI(cIDRemoveButton,	CPersistenList::OnRemoveUpdateUI)
	EVT_UPDATE_UI(cIDBlockOthers,	CPersistenList::OnBlockOthersUpdateUI)
	EVT_UPDATE_UI(cIDEditButton,	CPersistenList::OnEditUpdateUI)
END_EVENT_TABLE()

CPersistenList::CPersistenList(wxWindow* pParent, cMACBlockRuleId id ):
	wxPanel(pParent, 9000+id), m_pBlockOthers(NULL), m_pController(NULL)
{
	m_block.blockOthers = false;
	m_block.id = id;

	wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);

	sizer->Add(new wxStaticText(this, wxID_ANY,id == cMACBlockRuleIdWL?_("White List"):_("Black List")),
		0, wxALL|wxALIGN_CENTRE_HORIZONTAL, 5 );

	m_pList = new CLogCtrl<CPersistenList>(this, wxID_ANY, wxDefaultSize, true);
	sizer->Add(m_pList, 1, wxALL|wxEXPAND);

	m_pList->SetSingleStyle(wxLC_NO_HEADER);

	m_pList->InsertColumn( 0, _("MAC")  );
	//m_pList->SetColumnWidth( 0,		1000 );


	//Buttons
	wxBoxSizer* btnSizer = new wxBoxSizer(wxHORIZONTAL);

	m_pAddButtom = new wxButton(this, cIDAddButton, _("Add"), wxDefaultPosition, wxDefaultSize, wxNO_BORDER|wxBU_EXACTFIT );
	btnSizer->Add(m_pAddButtom, 0, wxLEFT|wxRIGHT|wxALIGN_LEFT, 10);

	if ( id == cMACBlockRuleIdWL )
	{
		wxButton* pEditButtom = new wxButton(this, cIDEditButton, _("Edit"), wxDefaultPosition, wxDefaultSize, wxNO_BORDER|wxBU_EXACTFIT );
		btnSizer->Add(pEditButtom, 0, wxLEFT|wxRIGHT|wxALIGN_LEFT, 10);

		btnSizer->AddStretchSpacer();
		m_pBlockOthers = new wxCheckBox(this, cIDBlockOthers, _("Block All others") );
		btnSizer->Add(m_pBlockOthers, 0, wxLEFT|wxRIGHT|wxALIGN_CENTER, 10);
		btnSizer->AddStretchSpacer();
	}
	else
	{
		btnSizer->AddStretchSpacer();
	}

	m_pRemoveButtom = new wxButton(this, cIDRemoveButton, _("Remove"), wxDefaultPosition, wxDefaultSize, wxNO_BORDER|wxBU_EXACTFIT );
	btnSizer->Add(m_pRemoveButtom, 0, wxLEFT|wxRIGHT|wxALIGN_RIGHT, 10);

	sizer->Add(btnSizer, 0, wxALL|wxEXPAND, 5);

	SetSizer(sizer);

	//Connect(wxEVT_SIZE, wxSizeEventHandler(CPersistenList::OnSize));
}

CPersistenList::~CPersistenList(void)
{
}

wxString CPersistenList::GetItemText(long item, long column, wxWindowID id)
{
	wxString str;

	try
	{
		str = wxString::FromAscii( m_block.list[item].strMAC.c_str() );
	}
	catch(...) {}


	return str;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////
// D&D
void CPersistenList::OnDragDropFinished( wxWindowID id, wxDragResult result)
{
	//RemoveSelected();
}


bool CPersistenList::OnDropText(wxCoord x, wxCoord y, const wxString& data)
{
	MACLIST listOut;

	TEXTLIST listIn = StrToList(data);
	
	for ( size_t i=0;i<listIn.size();i++ )
	{
		wxString strMAC =  ExtractMACFromString( wxString::FromAscii(listIn[i].c_str()) );
		if ( !strMAC.IsEmpty() )
		{
			MACENTRY entry;
			entry.strMAC = (const char*)strMAC.ToAscii();

			m_pController->GetItemFromPair(this, entry);
			
			listOut.push_back( entry );
		}
	}

	if ( !listOut.empty() && m_pController )
	{
		m_pController->OnAddItem(this, listOut);
	}

	return true;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////
// Logic
void CPersistenList::SetData(const MACBLOCK& block)
{
	assert( m_block.id == block.id );

	m_block = block;

	if ( m_pBlockOthers ) m_pBlockOthers->SetValue( m_block.blockOthers );

	((CLogCtrl<CPersistenList>*)m_pList)->DataChanged(true);
}

MACLIST CPersistenList::RemoveExisted(const MACLIST&	list) const
{
	MACLIST lstRes;

	for(size_t i=0;i<list.size();i++)
	{
		size_t j;

		for(j=0;j<m_block.list.size();j++)
		{
			if ( list[i].strMAC==m_block.list[j].strMAC )
				break;
		}

		if ( j==m_block.list.size() )
			lstRes.push_back( list[i] );
	}

	return lstRes;
}

void CPersistenList::RemoveItems(const MACLIST&	list)
{
	for(size_t i=0;i<list.size();i++)
	{
		for(MACLIST::iterator iCur=m_block.list.begin();
				iCur!=m_block.list.end();iCur++)
		{
			if ( list[i].strMAC == iCur->strMAC )
			{
				m_block.list.erase(iCur);
				break;
			}
		}
	}

	((CLogCtrl<CPersistenList>*)m_pList)->DataChanged(true);

	//If no one in list, remove block others check box
	if ( m_pBlockOthers&&m_block.blockOthers&&
		m_block.list.empty() )
	{
		m_pBlockOthers->SetValue(false);
		m_block.blockOthers = false;
	}

	assert(m_pController);
	m_pController->OnListChanged(this);
}

bool CPersistenList::CanAcceptItems( const MACLIST&	list )
{
	if ( cMACBlockRuleIdBL == m_block.id &&
		 IsOwnPCListed(list) )
	{
		wxMessageBox(_("You are trying to block your own PC! Operation failed."), _("Error"),
					 wxICON_WARNING | wxOK, this);
		return false;
	}

	return true;
}


bool CPersistenList::CanAddItems( const MACLIST&	list )
{
	if ( IsExistedInPair( list) )
	{
		wxMessageBox(_("MAC address already exists!"), _("Error"),
						 wxICON_WARNING | wxOK, this);
		return false;
	}

	return CanAcceptItems(list);
}

void CPersistenList::AddItems(const MACLIST&	list)
{
	MACLIST lstFiltered = RemoveExisted(list);

	for(size_t i=0;i<lstFiltered.size();i++)
		m_block.list.push_back(lstFiltered[i]);

	((CLogCtrl<CPersistenList>*)m_pList)->DataChanged(true);

	assert(m_pController);
	m_pController->OnListChanged(this);
}

bool CPersistenList::ExistInList(const MACENTRY& entry)
{
	bool bRes(false);

	for(MACLIST::iterator iCur=m_block.list.begin();
				iCur!=m_block.list.end();iCur++)
	{
		if ( iCur->strMAC == entry.strMAC )
		{
			bRes = true;
			break;
		}
	}

	return bRes;
}

bool CPersistenList::IsExistedInPair( const MACLIST&	list )
{
	return m_pController->IsExistedInPair( this, list );
}

bool CPersistenList::IsOwnPCListed( const MACLIST&	list )
{
	bool bRes(false);

	MACLIST	listInt = CSysDepAPI::GetPCInterfacesMACList();

	for (size_t i=0;i<list.size();i++)
	{
		wxString strMAC = wxString::FromAscii( list[i].strMAC.c_str() );

		for (size_t j=0;j<listInt.size();j++)
		{
			wxString strMACINT = wxString::FromAscii( listInt[j].strMAC.c_str() );

			if ( IsMACEqual( strMAC,  strMACINT) )
			{
				bRes = true;
				break;
			}
		}
	}

	return bRes;
}

///////////////////////////////////////////////////////////////////////////////////
//Msg Handlers
void CPersistenList::OnRemoveUpdateUI(wxUpdateUIEvent& event)
{
	assert(m_pList);

	if ( m_pList->IsEnabled() )
	{
		long item = -1;
		item = m_pList->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
		event.Enable(item != -1);
	}
	else
		event.Enable(false);
}

void CPersistenList::OnBlockOthersUpdateUI(wxUpdateUIEvent& event)
{
	if ( m_pBlockOthers ) event.Enable( !m_block.list.empty() ); 
}

//Add New
void CPersistenList::OnAdd(wxCommandEvent& ev)
{
	MACENTRY entry;
	CMACInputDlg dlg(m_block.id==cMACBlockRuleIdWL, entry);

	if ( dlg.Show() )
	{
		if ( ExistInList( entry ) )
		{
			wxMessageBox(_("MAC address already exists!"), _("Error"),
							 wxICON_WARNING | wxOK, this);
		}
		else
		{
			MACLIST lst;
			lst.push_back(entry);

			if ( CanAddItems(lst) )
			{
				AddItems(lst);
			}
		}
	}
}

void CPersistenList::OnEdit(wxCommandEvent& ev)
{
	long item = -1;
	item = m_pList->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);

    if ( item != -1 )
	{
		MACENTRY entry = m_block.list[item];
		CMACInputDlg dlg(m_block.id==cMACBlockRuleIdWL, entry, true);

		if ( dlg.Show() )
		{
			m_block.list[item] = entry;
		}
	}

	m_pController->OnListChanged(this);
}

void CPersistenList::OnEditUpdateUI(wxUpdateUIEvent& event)
{
	assert(m_pList);

	if ( m_pList->IsEnabled() )
	{
		size_t stCount=0;

		long item = -1;

		for ( ;; )
		{
			item = m_pList->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);

			if ( item == -1 )
				break;

			stCount++;
		}

		event.Enable(stCount==1);
	}
	else
		event.Enable(false);
}

void CPersistenList::OnRemove(wxCommandEvent& ev)
{
	assert(m_pList);

	MACLIST lst;

	long item = -1;

    for ( ;; )
    {
		item = m_pList->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);

        if ( item == -1 )
			break;

		lst.push_back( m_block.list[item] );
    }

	RemoveItems( lst );
}

void CPersistenList::OnBlockAll(wxCommandEvent& ev)
{
	assert(m_pBlockOthers);

	if ( m_pBlockOthers )
	{
		m_block.blockOthers = m_pBlockOthers->IsChecked();

		assert(m_pController);
		m_pController->OnListChanged(this);
	}
}


void CPersistenList::RemoveAll()
{
	bool bChanged(false);

	if ( !m_block.list.empty() )
	{
		m_block.list.erase(m_block.list.begin(),m_block.list.end() );
		((CLogCtrl<CPersistenList>*)m_pList)->DataChanged(true);

		bChanged = true;
	}

	//If no one in list, remove block others check box
	if ( m_pBlockOthers&&m_block.blockOthers )
	{
		m_pBlockOthers->SetValue(false);
		m_block.blockOthers = false;

		bChanged = true;
	}

	if ( bChanged )
	{
		wxGetApp().GetMainWnd()->GetPropStorage().SetMACList( m_block );
	}

}